﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;
using System.Diagnostics;
using AurelienRibon.Core.Options;

namespace CodeIn.Core {
	public class ResourceManager {
		private static ResourceManager instance = new ResourceManager();
		public static ResourceManager Instance { get { return instance; } }

		/// <summary>
		/// Gets the list of every paths defined in the resource file.
		/// </summary>
		public IDictionary<string, PathResource> Paths { get; private set; }

		/// <summary>
		/// Gets the list of every themes defined in the resource file.
		/// </summary>
		public IDictionary<string, ThemeResource> Themes { get; private set; }

		/// <summary>
		/// Ctor
		/// </summary>
		private ResourceManager() {
			Paths = new Dictionary<string, PathResource>();
			Themes = new Dictionary<string, ThemeResource>();

			Uri uri = new Uri("pack://application:,,,/resources/Resources.xml");
			var stream = App.GetResourceStream(uri).Stream;

			XDocument doc = XDocument.Load(stream);
			var pathElems = doc.Root.Element("Paths").Elements();
			var themeElems = doc.Root.Element("Themes").Elements();

			foreach (var elem in pathElems) {
				var res = GetPathResource(elem);
				Paths.Add(res.Name, res);
			}

			foreach (var elem in themeElems) {
				var res = GetThemeResource(elem);
				Themes.Add(res.Name, res);
			}

			var opt = new Option(
				"System.Ui.CurrentTheme",
				Themes.First().Key,
				false,
				null,
				(val, old) => { if (Themes.ContainsKey(val)) return val; return old; });

			OptionManager.Instance.RegisterOption(opt);
		}

		// --------------------------------------------------------------------
		// Private API
		// --------------------------------------------------------------------

		private PathResource GetPathResource(XElement elem) {
			Debug.Assert(elem.Name == "Path");
			string name = elem.Attribute("Name").Value;
			string type = elem.Attribute("Type").Value;
			string path = elem.Value.Trim();
			switch (type) {
				case "RelativeSpecial":
					string relativeTo = elem.Attribute("RelativeTo").Value;
					return PathResource.FromRelativeSpecial(name, path, relativeTo);
				case "PackUri":
					return PathResource.FromPackUri(name, path);
				default:
					Debug.Assert(false);
					return null;
			}
		}

		private ThemeResource GetThemeResource(XElement elem) {
			Debug.Assert(elem.Name == "Theme");
			string name = elem.Attribute("Name").Value;
			string filename = elem.Attribute("FileName").Value;
			string uri = Path.Combine(Paths["ThemeDirectoryUri"].Path, filename);
			return new ThemeResource(name, uri);
		}

		// --------------------------------------------------------------------
		// Classes
		// --------------------------------------------------------------------

		public class PathResource {
			public enum Types { PATH, URI }

			public string Name { get; private set; }
			public string Path { get; private set; }
			public Types Type { get; private set; }

			private PathResource(string name, string path, Types type) {
				Name = name;
				Path = path;
				Type = type;
			}

			public static PathResource FromRelativeSpecial(string name, string relativePath, string relativeTo) {
				var specialFolder = (Environment.SpecialFolder)Enum.Parse(typeof(Environment.SpecialFolder), relativeTo);
				string path = Environment.GetFolderPath(specialFolder);
				path = System.IO.Path.Combine(path, relativePath);
				return new PathResource(name, path, Types.PATH);
			}

			public static PathResource FromPackUri(string name, string packuri) {
				return new PathResource(name, packuri, Types.URI);
			}
		}

		public class ThemeResource {
			public string Name { get; private set; }
			public string Uri { get; private set; }

			public ThemeResource(string name, string uri) {
				Name = name;
				Uri = uri;
			}
		}
	}
}
